require 'rubygems'
require 'rtf'
require 'req_import_lib'

class RequirementsController < ApplicationController

  include RTF
  before_filter 'verify_session', :except=>[:index]

  def index
    p_id = params[:id]
    if p_id != nil
      @p_id = session[:selected_project] = p_id
      create_default_doc
      session[:selected_document] = ReqDoc.find(:first, :conditions=>["project_id=?",@p_id]).id
    end
    verify_session
    select_docs
    select_reqs
  end

  def add_form
    f_id = params[:father_id]
    @req = Req.new
    @req.priority = 3
    if f_id
      f = Req.find(f_id)
      @req.category = f.category
    end
    select_docs
    render(:partial=>'add_form', :locals=>{:father_id=>f_id})
  end 
  
  def create
    @req = Req.new(params[:req])
    @req.project_id = @p_id
    @req.status_date = Date.today()
    @errors = nil
    @errors = @req.errors.full_messages.join("\n") and return if not @req.save
    @father_id = params[:father_id]
    ReqRel.create(:project_id=>@p_id, :req_from_id=>@father_id, :req_to_id=>@req.id) if @father_id != nil
    @req_str = render_to_string(:partial=>'req', :object=>@req)
  end

  def req
    req = Req.find(params[:id])
    render(:partial=>'req', :object=>req) 
  end
  
  def edit_form
    @req = Req.find(params[:id])
    select_docs
    render(:partial=>'edit_form')
  end 
  
  def edit
    id = params[:req_id]
    data = params[:req]
    req = Req.find(id)
    req.status_date = Date.today() if req.status != data[:status] # can't check that after the update_attributes or 2 versions will be saved
    if not req.update_attributes(data) # do a save
      render(:text=>req.errors.full_messages.join('\n'), :status=>500) 
    else
      render(:partial=>'req', :object=>req) 
    end
  end
  
  def change_doc
    @d_id = session[:selected_document] = params[:id]
    select_reqs
    render(:partial=>'req', :collection=>@reqs) 
  end

  def change_doc
    @d_id = session[:selected_document] = params[:id]
    select_reqs
    render(:partial=>'req', :collection=>@reqs) 
  end
 
  def expand_req
    id = params[:id]
    sub = Req.find(id).subreqs.sort_by{|r| [r.priority, r.status, r.id]}
    sub = do_sort(sub)
    render(:partial=>'req', :collection=>sub) 
  end

  def sort_reqs
    session[:req_sort] = params[:sort]
    select_reqs
    render(:partial=>'req', :collection=>@reqs) 
  end
  
  def prepare_export
  end

  def prepare_import
  end

  def check_import
    @text = params[:import][:text]
    doc = ::ReqImportLib::Doc.new(:content=>@text)
    reqs = Req.find(:all, :conditions=>["project_id = ? ", @p_id]).collect {|r| [r.reference, r.text]} # , r.fathers.collect {|f| f.reference}
    doc.add_db(reqs)
    doc.flag_duplicates
    # fill in import table
    ReqImport.destroy_all(["user_id=? and project_id=?", session['user'], @p_id])
    doc.lines.each { |line|
      next if line.type != :req or line.result != :succeed
      req = ReqImport.create(:user_id=>session['user'], :project_id=>@p_id, :ref=>line.ref, :req=>line.req, :comments=>doc.comments(line.ref).join("\n"), :for_refs=>line.for_refs.join(';;'))
      line.id = req.id
      }
    @lines = doc.lines.select{|l| l.type == :req}.sort_by {|l| [l.ref]} 
    #@lines = ReqImport.find(:all, ["user_id=? and project_id=?", session['user'], @p_id])
    select_docs
  end
  
  def do_import
    reqs = ReqImport.find(:all, :conditions=>["user_id=? and project_id=?", session['user'], @p_id])
    reqs.each { |r|
      to = Req.create(:project_id=>@p_id, :priority=>2, :status=>10, :doc_id=>params[:req]["doc_id_#{r.id}"].to_i, :reference=>r.ref, :text=>r.req, :comments=>r.comments)
      # rels
      r.for_refs.split(';;').each { |text|
        from = Req.find_by_reference(text)
        ReqRel.create(:project_id=>@p_id, :req_to_id=>to.id, :req_from_id=>from.id) if from
        }
      }
    redirect_to(:action=>'index')  
  end
  
  def export
    inc_all = params[:export][:include_web_only].to_i
    inc_com = params[:export][:include_comments].to_i
    inc_rej = params[:export][:include_rejected].to_i
    response.headers['Content-type'] = 'application/rtf; charset=utf-8' 
    response.headers['Content-Disposition'] = "attachment; filename=Requirements.rtf"
    render(:text=>create_rtf(inc_all, inc_com, inc_rej))
  end
  
  def bulk_edit
    @ids    = params[:id]
    @action = params[:action_name]
    render(:text=>'No requirement selected') and return if @ids == nil
    @reqs = Req.find(:all, :conditions=>"id in (#{@ids.join(',')})")
    case @action
    when 'move'
      move_action
    when 'prio'
      prio_action
    else
      render(:text=>"'#{action}' not implemented, ids=#{@ids}")
    end
    return
  end

  def move_action
    @docs = ReqDoc.find(:all, :conditions=>["project_id=?",@p_id])
    render(:template=>'requirements/move_action')
  end
  
  def prio_action
    @prios = PRIO
    render(:template=>'requirements/prio_action')
  end

  def do_move
    ids = params[:ids].split(",")
    doc_id = params[:form][:doc_id]
    ids.each { |id|
      r = Req.find(id)
      r.doc_id = doc_id
      r.save
      }
    redirect_to "/requirements"
  end

  def do_prio
    ids = params[:ids].split(",")
    prio = params[:prio]
    ids.each { |id|
      r = Req.find(id)
      r.priority = prio
      r.save
      }
    redirect_to "/requirements"
  end
  
  def wipe_all
    Req.destroy_all(["project_id", @p_id])  
    ReqRel.destroy_all(["project_id", @p_id])  
    redirect_to "/requirements"
  end
  
  def traceability
    # not derived reqs
    @down = Req.find(:all, :conditions=>["project_id = ? and (select count(id) from req_rels where req_rels.req_from_id=reqs.id)=0",@p_id])
    # no upward reqs
    @up   = Req.find(:all, :conditions=>["project_id = ? and (select count(id) from req_rels where req_rels.req_to_id=reqs.id)=0",@p_id])
    #
    @reqs = Req.find(:all, :conditions=>["project_id = ?",@p_id], :order=>"reference")
  end
  
#################################################################
private

  def verify_session
    redirect_to "/" if session['user'] == nil 
    @p_id = session[:selected_project]
    #raise 'no project' @p_id == nil or @p_id == '0'
    @d_id = session[:selected_document]
    @d_id = ReqDoc.find(:first, :conditions=>["project_id=?",@p_id]).id if @d_id == nil or @d_id == '0'
  end
  
  def create_default_doc
    if ReqDoc.count(:conditions=>["project_id=?",@p_id])==0
      session[:selected_document] = ReqDoc.create_default(@p_id).id
    end
  end

  def select_docs
    @docs = ReqDoc.find(:all, :conditions=>["project_id=?",@p_id])
  end
  
  def select_reqs(doc_id=nil)
    doc_id = @d_id if not doc_id
    @reqs = Req.find(:all, :conditions=>["project_id = ? and doc_id=? and (select count(id) from req_rels where req_rels.req_to_id=reqs.id)=0",@p_id, doc_id])
    @reqs = do_sort(@reqs)
  end
  
  def do_sort(reqs)
    case session[:req_sort]
    when nil,'', 'prio'
      reqs.sort_by { |r| [(r.priority||0),(r.status||0),r.id] }
    when 'status'
      reqs.sort_by { |r| [(r.status||0),(r.priority||0),r.id] }
    when 'cat'
      reqs.sort_by { |r| [(r.category||0),(r.priority||0),r.id] }
    when 'ref'
      reqs.sort_by { |r| [(r.reference||''), r.text] }
    end
  end
  
############
# RTF Export
############

  def create_rtf(inc_web_only, inc_comments, inc_rejected)
    rtf_set_vars
    rtf = Document.new(@fonts[0])
    @docs = ReqDoc.find(:all, :conditions=>["project_id=?",@p_id])
    @docs.each { |d|
      rtf_export_reqs_by_doc(rtf, d, inc_web_only, inc_comments, inc_rejected)
      }
    rtf.to_rtf
  end
  
  def rtf_export_reqs_by_doc(rtf, doc, inc_web_only, inc_comments, inc_rejected)
    select_reqs(doc.id)
    rtf.paragraph(@styles['PS_DOC_TITLE']).apply(@styles['CS_DOC_TITLE']) << "#{doc.title}"
    @reqs.each { |r|
      next if (inc_web_only==0 and r.web_only==1) or (inc_rejected==0 and r.status==130)
      rtf.paragraph(@styles['PS_REQ_NORMAL']) do |p|
        p.apply(@styles['CS_TEXT']).bold << "#{r.reference}"
        p.apply(@styles['CS_TEXT']) << " #{r.text}"
        if r.rationale and r.rationale != ''
          p.line_break
          p.apply(@styles['CS_RATIONALE']) << "Rationale: #{r.rationale}"
        end
        if inc_comments==1 and r.comments and r.comments != ''
          p.line_break
          p.apply(@styles['CS_RATIONALE']) << "Comments: #{r.comments}"
        end
        p.apply(@styles['CS_TEXT']) << ""
      end
      }
  end

  def rtf_set_vars
    @fonts = [Font.new(Font::ROMAN, 'Arial'),
             Font.new(Font::MODERN, 'Courier')]

    @styles = {}
    @styles['PS_DOC_TITLE']              = ParagraphStyle.new
    @styles['PS_DOC_TITLE'].space_before   = 200
    @styles['PS_DOC_TITLE'].space_after    = 100

    @styles['CS_DOC_TITLE']              = CharacterStyle.new
    @styles['CS_DOC_TITLE'].bold         = true
    @styles['CS_DOC_TITLE'].font_size    = 24

    @styles['PS_REQ_NORMAL']             = ParagraphStyle.new
    @styles['PS_REQ_NORMAL'].left_indent = 100

    @styles['CS_TEXT']              = CharacterStyle.new
    @styles['CS_TEXT'].font_size    = 18
    @styles['CS_RATIONALE']              = CharacterStyle.new
    @styles['CS_RATIONALE'].font_size    = 16
    @styles['CS_RATIONALE'].italic    = true
  end

  
end

